/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  ClassDeclaration,
  EnumDeclaration,
  InterfaceDeclaration,
  SourceFile,
  TypeAliasDeclaration
} from 'ts-morph';
import {
  ClassDetails,
  EnumDetails,
  EnumMemberInfo,
  InterfaceDetails,
  TypeAliasDetails,
  TypeDependency,
  TypeDetails,
  TypeKind
} from '..';
import SerializationPathUtil from '../utils/SerializationPathUtil';
import { TsMorphUtil } from '../utils/TsMorphUtil';

export class CustomTypeAnalyzer {
  private static readonly INSTANCE: CustomTypeAnalyzer = new CustomTypeAnalyzer();
  /** 类型查找缓存 <名称+路径，依赖地址> */
  private searchCache = new Map<string, TypeDependency | null>();

  private constructor() { }

  public static getInstance(): CustomTypeAnalyzer {
    return this.INSTANCE;
  }

  /**
   * 类型查找方法-实现本文件-->本模块-->跨模块三步走查找逻辑
   *
   * @param targetName 目标类型名称
   * @param sourceFile 起始源文件
   * @returns 查找结果，未找到时返回 null
   */
  public findDefinition(targetName: string, sourceFile: SourceFile): TypeDependency | null {
    const cacheKey = `${sourceFile.getFilePath()}:${targetName}`;

    // 检查缓存
    if (cacheKey && this.searchCache.has(cacheKey)) {
      const cached = this.searchCache.get(cacheKey);
      return cached !== undefined ? cached : null;
    }

    let result: TypeDependency | null;

    // 步骤1：在当前文件中查找
    result = this.findInCurrentFile(targetName, sourceFile);
    if (result) {
      if (cacheKey) {
        this.searchCache.set(cacheKey, result);
      }
      return result;
    }

    // 步骤2：根据导入语句查找本模块内的类型定义
    result = this.findInImports(targetName, sourceFile);
    if (result) {
      if (cacheKey) {
        this.searchCache.set(cacheKey, result);
      }
      return result;
    }

    // 步骤3：查找oh_modules中的跨模块类型定义
    result = this.findInCrossModule(targetName, sourceFile);
    if (result) {
      if (cacheKey) {
        this.searchCache.set(cacheKey, result);
      }
      return result;
    }

    // 缓存未找到的结果
    if (cacheKey) {
      this.searchCache.set(cacheKey, null);
    }
    return null;
  }

  public findClassDeclFromClassName(className: string, sourceFile: SourceFile): ClassDeclaration | InterfaceDeclaration | null {
    const res = this.findDefinition(className, sourceFile);
    if (res && res.typeKind === TypeKind.CLASS) {
      return (res.details as ClassDetails).classDecl;
    }
    if (res && res.typeKind === TypeKind.INTERFACE) {
      return (res.details as InterfaceDetails).interfaceDecl;
    }
    return null;
  }

  public clearCache(): void {
    this.searchCache.clear();
  }

  private findInCurrentFile(targetName: string, sourceFile: SourceFile): TypeDependency | null {
    const typeDetail = this.searchInSourceFile(targetName, sourceFile);
    if (typeDetail) {
      return {
        typeName: targetName,
        typeKind: typeDetail.kind,
        importPath: '',
        source: {
          type: 'local',
          sourceFilePath: sourceFile.getFilePath()
        },
        details: typeDetail
      };
    }
    return null;
  }

  private findInImports(targetName: string, sourceFile: SourceFile): TypeDependency | null {
    const imports = sourceFile.getImportDeclarations();

    for (const importDecl of imports) {
      // TODO:当前实现只处理命名导入，default导入和命名空间导入暂未支持
      const namedImports = importDecl.getNamedImports();
      const specifierValue = importDecl.getModuleSpecifierValue();

      // 检查是否在命名导入中找到了目标类型
      for (const namedImport of namedImports) {
        const importName = namedImport.getName();
        if (importName === targetName) {
          // 找到了导入的类型，现在需要解析文件路径
          const moduleSpecifier = importDecl.getModuleSpecifierValue();
          const resolvedPath = this.resolveImportPath(moduleSpecifier, sourceFile);

          if (resolvedPath && SerializationPathUtil.exist(resolvedPath)) {
            // 加载外部文件并查找类型定义
            const externalSourceFile = this.getOrLoadSourceFile(resolvedPath);
            if (externalSourceFile) {
              const typeDetail = this.searchInSourceFile(targetName, externalSourceFile);
              if (typeDetail) {
                return {
                  typeName: targetName,
                  typeKind: typeDetail.kind,
                  importPath: specifierValue,
                  source: {
                    type: 'imported',
                    sourceFilePath: externalSourceFile.getFilePath(),
                    originalImport: specifierValue
                  },
                  details: typeDetail
                };
              }
            }
          }
        }
      }
    }

    return null;
  }

  private findInCrossModule(targetName: string, sourceFile: SourceFile): TypeDependency | null {
    // TODO: 跨模块暂未实现
    return null;
  }

  private searchInSourceFile(targetName: string, sourceFile: SourceFile): TypeDetails | null {
    // 查找类定义
    const classes = sourceFile.getClasses();
    for (const classDecl of classes) {
      if (classDecl.getName() === targetName) {
        return this.parseClassDetails(classDecl);
      }
    }

    // 查找接口定义
    const interfaces = sourceFile.getInterfaces();
    for (const interfaceDecl of interfaces) {
      if (interfaceDecl.getName() === targetName) {
        return this.parseInterfaceDetails(interfaceDecl);
      }
    }

    // 查找枚举定义
    const enums = sourceFile.getEnums();
    for (const enumDecl of enums) {
      if (enumDecl.getName() === targetName) {
        return this.parseEnumDetails(enumDecl);
      }
    }

    // 查找类型定义
    const types = sourceFile.getTypeAliases();
    for (const typeAliasDecl of types) {
      if (typeAliasDecl.getName() === targetName) {
        return this.parseTypeAliasDetails(typeAliasDecl);
      }
    }

    return null;
  }

  private parseEnumDetails(enumDecl: EnumDeclaration): EnumDetails {
    const members: EnumMemberInfo[] = [];
    let valueType: 'string' | 'number' = 'number'; // 默认为数值类型
    let numericValue = 0; // 用于自动递增的数值

    const enumMembers = enumDecl.getMembers();
    for (const member of enumMembers) {
      const memberName = member.getName();
      let memberValue: string | number;
      let literalValue: string;

      const initializer = member.getInitializer();
      if (initializer) {
        // 有显式初始值
        const initText = initializer.getText().trim();

        // 判断是字符串还是数值
        if (initText.startsWith('"') && initText.endsWith('"')) {
          // 字符串枚举
          memberValue = initText.slice(1, -1); // 去掉引号
          literalValue = initText; // 保留引号
          valueType = 'string';
        } else if (initText.startsWith("'") && initText.endsWith("'")) {
          // 字符串枚举（单引号）
          memberValue = initText.slice(1, -1); // 去掉引号
          literalValue = `"${memberValue}"`; // 统一使用双引号
          valueType = 'string';
        } else {
          // 数值枚举
          const numValue = parseInt(initText, 10);
          if (!isNaN(numValue)) {
            memberValue = numValue;
            literalValue = numValue.toString();
            numericValue = numValue + 1; // 更新下一个自动值
          } else {
            // 复杂表达式，暂时当作字符串处理
            memberValue = initText;
            literalValue = `"${initText}"`;
            valueType = 'string';
          }
        }
      } else {
        // 没有显式初始值，使用自动递增的数值
        memberValue = numericValue;
        literalValue = numericValue.toString();
        numericValue++;
      }
      members.push({
        name: memberName,
        value: memberValue,
        literalValue
      });
    }
    return { kind: TypeKind.ENUM, valueType, members };
  }

  private parseClassDetails(classDecl: ClassDeclaration): ClassDetails {
    return {
      kind: TypeKind.CLASS,
      classDecl,
      isGeneric: classDecl.getTypeParameters().length > 0
    };
  }

  private parseInterfaceDetails(interfaceDecl: InterfaceDeclaration): InterfaceDetails {
    return {
      kind: TypeKind.INTERFACE,
      interfaceDecl,
      isGeneric: interfaceDecl.getTypeParameters().length > 0
    };
  }

  private parseTypeAliasDetails(typeAliasDecl: TypeAliasDeclaration): TypeAliasDetails {
    const aliasedType = typeAliasDecl.getTypeNodeOrThrow().getText();

    // 解析实际类型节点，填充 resolvedType
    const actualTypeNode = typeAliasDecl.getTypeNodeOrThrow();
    const { TypeHandlerRegistry } = require('../handlers/TypeHandlerRegistry');

    // 递归解析实际类型结构
    const resolvedType = TypeHandlerRegistry.getInstance().parseType(actualTypeNode, {
      depth: 0,
      genericParams: []
    });

    return { kind: TypeKind.TYPE, aliasedType, resolvedType };
  }

  private resolveImportPath(moduleSpecifier: string, sourceFile: SourceFile): string | null {
    const currentFilePath = sourceFile.getFilePath();
    const currentDir = SerializationPathUtil.dirname(currentFilePath);

    // 处理相对路径导入
    if (moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../')) {
      const resolvedPath = SerializationPathUtil.pathResolve(currentDir, moduleSpecifier);

      // 尝试不同的文件扩展名
      const extensions = ['.ets', '.d.ets'];
      for (const ext of extensions) {
        const fullPath = resolvedPath + ext;
        if (SerializationPathUtil.exist(fullPath)) {
          return fullPath;
        }
      }
    }

    return null;
  }

  private getOrLoadSourceFile(filePath: string): SourceFile | null {
    const existingFile = TsMorphUtil.getProject().getSourceFile(filePath);
    if (existingFile) {
      return existingFile;
    }

    if (SerializationPathUtil.exist(filePath)) {
      return TsMorphUtil.getProject().addSourceFileAtPath(filePath);
    }

    return null;
  }
}
